/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 *
 *           File:  main.cpp
 *    Description:  test for noisproof XOR code (?? XOR code similar to CRC)
 *       
 *        Created:  16.02.2013 01:25:51
 *         Author:  Aleksey Golovchenko (lexgolovchenko@gmail.com)
 *   Organization:  St.Petersburg State Polytecnical Universisy
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <systemc.h>

#include <stdlib.h>
#define RANDU ((double)rand())/RAND_MAX

#define FRAME_NUM 16
sc_uint<32> frame[FRAME_NUM];
int err_cntr = 0;

// print frame to stdout
void display_frame() 
{
    for (int i = 0; i < FRAME_NUM; ++i) {
        printf("%-9.8X", frame[i].to_uint());
    } 
    printf("\n");
}

// prepare frame and calculate XOR-code
void xor_coding() 
{
    for (int i = 0; i < FRAME_NUM; ++i) {
        frame[i] = rand();
    } 

    sc_uint<32> xor_code = 0;
    for (int i = 0; i < FRAME_NUM - 1; ++i) {
        xor_code ^= frame[i];
    } 
    frame[15] = xor_code;    

    display_frame();
}

// add noise
void add_noise(double p) 
{
    sc_uint<32> err;
    for (int i = 0; i < FRAME_NUM; ++i) {        

        err = 0;        
        for (int j = 0; j < 32; ++j) {
            err[j] = (RANDU < p);
            err_cntr += err[j];
        }

        printf("%-9.8X", err.to_uint());

        frame[i] ^= err;
    } 
    printf("\n");
}

// check XOR-code
int check_xor() 
{
    sc_uint<32> xor_code = 0;
    for (int i = 0; i < FRAME_NUM - 1; ++i) {
        xor_code ^= frame[i];
    } 

    display_frame();

    return xor_code == frame[15];
}

int sc_main(int argc, char **argv) 
{
    if (argc < 2) {
        printf("Usage : %s err_probability \n", argv[0]);
    }

    // error probability
    double p = atof(argv[1]);

    srand(time(NULL));

    // prepare frame
    xor_coding();   

    // add uniform random noise (binary simmetric channel)
    add_noise(p);    

    // check XOR-code
    if (!check_xor()) {
        printf("Wrong frame! Error counter %d \n", err_cntr);
    }
    
    return 0;
}
